﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Common.Tools.Encrypt
{
    public class RSA
    {
        #region Rsa 非对称加密
        /// <summary>
        /// 加密并获取公钥和私钥
        /// </summary>
        /// <param name="content"></param>
        /// <param name="publicKey"></param>
        /// <param name="privateKey"></param>
        /// <returns></returns>
        public static string Encrypt(string content, out string publicKey, out string privateKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            publicKey = rsa.ToXmlString(false);
            privateKey = rsa.ToXmlString(true);

            UnicodeEncoding byteConverter = new UnicodeEncoding();
            byte[] dataToEncrypt = byteConverter.GetBytes(content);
            byte[] resultBytes = rsa.Encrypt(dataToEncrypt, false);
            return Convert.ToBase64String(resultBytes);
        }
        /// <summary>
        /// 获取密钥对(publicKey,privateKey)
        /// </summary>
        /// <returns>publicKey,privateKey</returns>
        public static KeyValuePair<string, string> GetKeyPair()
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            string publicKey = rsa.ToXmlString(false);
            string privateKey = rsa.ToXmlString(true);
            return new KeyValuePair<string, string>(publicKey, privateKey);
        }
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="content"></param>
        /// <param name="publicKey"></param>
        /// <param name="privateKey"></param>
        /// <returns></returns>
        public static string Encrypt(string content, string publicKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(publicKey);

            UnicodeEncoding byteConverter = new UnicodeEncoding();
            byte[] dataToEncrypt = byteConverter.GetBytes(content);
            int maxStrSize = rsa.KeySize / 8 - 11;    //加密块最大长度限制

            if (dataToEncrypt.Length <= maxStrSize)
                return Convert.ToBase64String(rsa.Encrypt(dataToEncrypt, false));

            using (MemoryStream msContent = new MemoryStream(dataToEncrypt))
            using (MemoryStream msWrite = new MemoryStream())
            {
                byte[] buffer = new byte[maxStrSize];
                int count = msContent.Read(buffer, 0, maxStrSize);
                while (count > 0)
                {
                    byte[] copyBuffer = new byte[count];
                    Array.Copy(buffer, 0, copyBuffer, 0, count);

                    byte[] toBuffer = rsa.Encrypt(copyBuffer, false);
                    msWrite.Write(toBuffer, 0, toBuffer.Length);

                    count = msContent.Read(buffer, 0, maxStrSize);
                }

                return Convert.ToBase64String(msWrite.ToArray());
            }
        }
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="content"></param>
        /// <param name="privateKey"></param>
        /// <returns></returns>
        public static string Decrypt(string content, string privateKey)
        {
            byte[] dataToDecrypt = Convert.FromBase64String(content);
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(privateKey);

            int maxStrSize = rsa.KeySize / 8;    //解密块最大长度限制

            if (dataToDecrypt.Length <= maxStrSize)
                return new UnicodeEncoding().GetString(rsa.Decrypt(dataToDecrypt, false));

            using (MemoryStream msContent = new MemoryStream(dataToDecrypt))
            using (MemoryStream msWrite = new MemoryStream())
            {
                byte[] buffer = new byte[maxStrSize];
                int count = msContent.Read(buffer, 0, maxStrSize);
                while (count > 0)
                {
                    byte[] toBuffer = rsa.Decrypt(buffer, false);
                    msWrite.Write(toBuffer, 0, toBuffer.Length);

                    count = msContent.Read(buffer, 0, maxStrSize);
                }
                return new UnicodeEncoding().GetString(msWrite.ToArray());
            }
        }
        #endregion
    }
}
